Skip to content

Conversation

@shore
Copy link

@shore shore commented Aug 12, 2015

Hi,
We like to reuse our middleware functions for various endpoints and like to put them in named functions. We have some composition functions that make this easy. In particular, we can compose individual middleware functions into chains, or we can compose more middleware functions onto the end of a chain. This also creates fewer anonymous functions than rewrapping all middleware for each endpoint.

http://play.golang.org/p/MQ5iTyr789

ReduceMW is analogous to the reduce / foldl functions. The composer is written such that the first MW function in the composition is the first one called, but it can trivially be replaced / altered to reverse the order if someone prefered the first function in the composition to instead be closest to the endpoint in the recursion.

@peterbourgon
Copy link
Member

Hi, thanks for the contribution! I'm in favor of adding a helper type to chain middlewares, to avoid having to do it the manual way. But I'm not immediately convinced by your API, and I definitely wouldn't bake in an abbreviation like "MW" :) Have you seen https://github.com/justinas/alice? What do you think of that model? Is there something missing from an API like e.g.

// Current
var e endpoint.Endpoint
e = myEndpoint
e = inner(param)(e)
e = outer(key, val)(e)

// Proposed e.g.
e := endpoint.Chain(outer(key, val), inner(param), myEndpoint)

@anarcher
Copy link

+1 I like it like Ailce. In my very simple code,It looks like ChainMiddeware :-)

func Chain(middewares ...endpoint.Middleware) func(endpoint.Endpoint) endpoint.Endpoint {
    return func(e endpoint.Endpoint) endpoint.Endpoint {
        for i := len(middewares) - 1; i >= 0; i-- { // reverse
            e = middewares[i](e) 
        }
        return e
    }
}

mw1 := outer(key,val)
mw2 := inter(params)
e1 := endpoint.Chain(mw1,mw2)(e1)
e2 := endpoint.Chain(mw1,mw2)(e2)

@shore
Copy link
Author

shore commented Aug 14, 2015

I'm not particularly attached to function names or recursion vs. iteration. I do think that Chain should not be passed an endpoint, rather it should simply return a Middleware (chain) that can subsequently be applied to multiple endpoints (as in @anarcher's sample function) -- there's no point in rebuilding the same chain for multiple endpoints.

Also, I think Chain is better written to require at least one Middlware. There's no reason to call Chain() if no Middleware is being passed, and if none are passed, there's no good return value without also returning an error (as the wrapper around the endpoint does nothing useful in that case).

How about this:

func Chain(outer Middleware, others ...Middleware) Middleware {
    return func(e Endpoint) Endpoint {
        for i := len(others) - 1; i >= 0; i-- { // reverse
            e = others[i](e)
        }
        return outer(e)
    }
}

@anarcher
Copy link

@shore It's better than my simple func. 👍 :-)

peterbourgon added a commit that referenced this pull request Aug 14, 2015
peterbourgon added a commit that referenced this pull request Aug 14, 2015
peterbourgon added a commit that referenced this pull request Aug 14, 2015
peterbourgon added a commit that referenced this pull request Aug 15, 2015
peterbourgon added a commit that referenced this pull request Aug 15, 2015
@peterbourgon
Copy link
Member

Closed via #96! Thanks for the suggestion!

@ChrisHines ChrisHines mentioned this pull request May 30, 2016
9 tasks
guycook pushed a commit to codelingo/kit that referenced this pull request Oct 12, 2016
guycook pushed a commit to codelingo/kit that referenced this pull request Oct 12, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants